<?php

namespace App\Models\Plane\PlaneOrderPassengers\Repositories;

use App\Models\Plane\PlaneOrderPassengers\PlaneOrderPassenger;
use App\Models\Plane\PlaneOrderPassengers\Repositories\Interfaces\PlaneOrderPassengerRepositoryInterface;
use App\Models\Plane\PlaneOrders\PlaneOrder;
use App\Models\Plane\PlaneOrders\Repositories\Interfaces\PlaneOrderRepositoryInterface;
use App\Models\Trip\TripOrderCosts\Repositories\TripOrderPassengerCostsRepository;
use App\Models\Trip\TripOrderCosts\TripOrderCost;
use App\Models\Trip\TripOrderRefund\TripOrderRefund;
use App\Trip\Orders\TripOrderState;
use App\Trip\Plane\OrderSelectedPassengers;
use App\Trip\Repository\BaseRepository;
use App\Trip\Train\Order\Interfaces\OrderPassengerRefundInterface;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\DB;
use Throwable;

class PlaneOrderPassengerRepository extends BaseRepository implements PlaneOrderPassengerRepositoryInterface
{
    public function __construct(PlaneOrderPassenger $model)
    {
        parent::__construct($model);
    }

    /**
     * 批量添加乘客
     * @param PlaneOrder  $order
     * @param             $passengers_data
     * @return bool
     * @throws Exception
     */
    public function addPassengers(PlaneOrder $order, $passengers_data): bool
    {
        $passengers      = [];
        $passenger_costs = [];
        foreach ($passengers_data as $key => $passenger) {
            [$sequence, $passengers] = $this->extracted($passenger, $key, $order, $passengers);
            $passenger_costs = $this->getPassengerCosts($passenger, $order, $sequence, $passenger_costs);
        }
        // passenger costs
        $passengerCostRepo = app(TripOrderPassengerCostsRepository::class);
        $passengerCostRepo->addMore($passenger_costs);
        return $this->model->insert($passengers);
    }

    /**
     * @param             $passenger
     * @param int|string  $key
     * @param PlaneOrder  $order
     * @param array       $passengers
     * @return array
     */
    private function extracted($passenger, int|string $key, PlaneOrder $order, array $passengers): array
    {
        $sequence         = $this->getSequence($passenger['sequence'], $key);
        $passengers[$key] = [
            'order_sn'                => $order->getOrderSn(),
            'user_id'                 => $order->getUserId(),
            'change_flag'             => $order->getChangeFlag(),
            'sequence'                => $sequence,// 序号
            'passenger_id'            => $passenger['passenger_id'],
            'truename'                => $passenger['truename'],
            'identity_type'           => $passenger['identity_type'],
            'identity_code'           => $passenger['identity_code'],
            'passenger_type'          => $passenger['passenger_type'],
            'mobile'                  => $passenger['mobile'],
            'ticket_price'            => $passenger['ticket_price'],
            'total_price'             => $passenger['total_price'],
            'construct_fee'           => $passenger['construct_fee'],
            'fuel_fee'                => $passenger['fuel_fee'],
            'service_fee'             => $passenger['service_fee'],
            'cabin'                   => $passenger['cabin'],
            'origin_ticket_number'    => $passenger['origin_ticket_number'] ?? '',
            'origin_sub_out_order_id' => $passenger['origin_sub_out_order_id'] ?? '',
            'origin_cabin'            => $passenger['origin_cabin'] ?? '',
            'origin_fuel_fee'         => $passenger['origin_fuel_fee'] ?? 0,
            'origin_construct_fee'    => $passenger['origin_construct_fee'] ?? 0,
            'change_fee'              => $passenger['change_fee'] ?? 0,
            'ticket_price_diff'       => $passenger['ticket_price_diff'] ?? 0,
            'fuel_fee_diff'           => $passenger['fuel_fee_diff'] ?? 0,
            'construction_fee_diff'   => $passenger['construction_fee_diff'] ?? 0,
            'provider_ticket_price'   => 0, // 支付后 更新  改签的无法得知
            'order_state'             => $order->getOrderState(),// 订单状态
            'change_ticket_loss'      => $passenger['change_ticket_loss'] ?? 0,// 改签票损
            'provider_price_state'    => $passenger['provider_price_state'] ?? 0,// 价格确认状态
            'upgrade_fee'             => $passenger['upgrade_fee'] ?? 0,// 升舱费
            'origin_ticket_price'     => $passenger['origin_ticket_price'] ?? 0,// 原票价
        ];
        return [$sequence, $passengers];
    }

    /**
     * @param            $sequence1
     * @param int|string $key
     * @return int|string
     */
    private function getSequence($sequence1, int|string $key): string|int
    {
        $sequence = $sequence1 ?? 0;
        return $sequence ?: $key + 1;
    }

    /**
     * @param             $passenger
     * @param PlaneOrder  $order
     * @param mixed       $sequence
     * @param array       $passenger_costs
     * @return array
     */
    private function getPassengerCosts($passenger, PlaneOrder $order, mixed $sequence, array $passenger_costs): array
    {
        foreach ($passenger['price_details'] as $price_detail) {
            $passenger_costs [] = [
                "user_id"       => $order->getUserId(),
                "trip_id"       => $order->getTripId(),
                "trip_type"     => $order->getTripType(),
                "order_sn"      => $order->getOrderSn(),
                "passenger_id"  => $passenger['passenger_id'],
                "sequence"      => $sequence,
                "type"          => $price_detail["type"],
                "parent_type"   => $price_detail["type"],
                "price"         => $price_detail["price"],
                "name"          => $price_detail["name"],
                "detail"        => $price_detail["detail"] ?? "",
                "confirm_state" => $price_detail["confirm_state"] ?? TripOrderCost::COST_STATE_CONFIRMED, //价格确认状态 1 已确认 0 待确认
            ];
        }
        return $passenger_costs;
    }

    /**
     * @param PlaneOrder  $order
     * @param             $data
     * @return PlaneOrderPassenger
     */
    public function addOnePassenger(PlaneOrder $order, $data): PlaneOrderPassenger
    {
        $data['user_id']  = $order->getUserId();
        $data['order_sn'] = $order->getOrderSn();
        return $this->create($data);
    }

    /**
     * @param string $order_sn
     * @param string $passenger_id
     * @param int    $sequence
     * @return PlaneOrderPassenger
     */
    public function findOneOrderPassenger(string $order_sn, string $passenger_id, int $sequence): PlaneOrderPassenger
    {
        return $this->findOneBy([
            'order_sn'     => $order_sn,
            'passenger_id' => $passenger_id,
            'sequence'     => $sequence,
        ]);
    }

    /**
     * @param PlaneOrderPassenger $passenger
     * @param array               $data
     * @return bool
     */
    public function updatePassenger(PlaneOrderPassenger $passenger, array $data): bool
    {
        return $this->update($data, $passenger);
    }

    /**
     * @param OrderPassengerRefundInterface $order_passenger_refund
     * @return TripOrderRefund
     * @throws Exception
     */
    public function refund(OrderPassengerRefundInterface $order_passenger_refund): TripOrderRefund
    {
        throw new Exception("已废弃单乘客退款");
    }

    /**
     * @param PlaneOrder       $order_info
     * @param                  $passengers
     * @param TripOrderRefund  $refund_info
     * @
     * @throws Throwable
     */
    public function ticketReturnSuccess(PlaneOrder $order_info, $passengers, TripOrderRefund $refund_info)
    {


        DB::transaction(function () use ($order_info, $passengers, $refund_info) {
            $op = new OrderSelectedPassengers($order_info, $passengers);
            // 退款详情状态标记为 退款中
            $refund_info->update([
                'refund_state' => TripOrderRefund::REFUND_STATE_REFUNDING,
                'refund_at'    => Carbon::now()->toDateTimeString(),
            ]);

            // 订单状态标记为 验证是否是部分乘客
            $order_state = $op->isPartPassengers() ? TripOrderState::ORDER_STATE_REFUNDED_PART : TripOrderState::ORDER_STATE_REFUNDED;
            $orderRepo   = app(PlaneOrderRepositoryInterface::class);
            $orderRepo->updateOrderState($order_info, [
                'order_state' => $order_state,
            ], collect($passengers));
        });

//        $order_info->notify(new TicketReturnSuccessNotify($order_info, $refund_info));
    }

    /**
     * @param PlaneOrder       $order_info
     * @param                  $passengers
     * @param TripOrderRefund  $refund_info
     * @param string           $failed_reason
     * @return void
     * @throws Throwable
     */
    public function ticketReturnFailed(PlaneOrder $order_info, $passengers, TripOrderRefund $refund_info, string $failed_reason): void
    {
        DB::transaction(function () use ($order_info, $passengers, $refund_info, $failed_reason) {
            $refund_info->update([
                'refund_state'  => TripOrderRefund::REFUND_STATE_TICKET_RETURN_FAILED,
                'failed_reason' => $failed_reason,
            ]);

            $orderRepo = app(PlaneOrderRepositoryInterface::class);
            $orderRepo->updateOrderState($order_info, [
                'order_state' => TripOrderState::ORDER_STATE_REFUND_FAILED,
            ], collect($passengers));
        });

//        $order_info->notify(new TicketReturnFailedNotify($order_info));
    }

    /**
     * 通过外部子单id 查询订单
     * @param string $sub_out_order_id
     * @return PlaneOrder|null
     * @throws Exception
     */
    public function getOrderInfoBySubOutOrderId(string $sub_out_order_id): ?PlaneOrder
    {
        if (!$sub_out_order_id) {
            throw new Exception("请传入订单单号");
        }

        $p = $this->findOneByOrFail([
            'sub_out_order_id' => $sub_out_order_id,
        ]);
        return $p?->order_info;
    }

    /**
     * 通过订单号和证件号匹配乘客
     * @param string $order_sn
     * @param string $identity_code
     * @return PlaneOrderPassenger
     */
    public function findOneByIdentityCode(string $order_sn, string $identity_code): PlaneOrderPassenger
    {
        return $this->findOneBy([
            'order_sn'      => $order_sn,
            'identity_code' => $identity_code,
        ]);
    }

    public function findOneByNameAndTicketNumber(string $true_name, string $ticket_number, ?PlaneOrder $order_info = null): ?PlaneOrderPassenger
    {
        $condition = [
            'truename'      => $true_name,
            'ticket_number' => $ticket_number,
        ];
        $order_info?->getOrderSn() && $condition['order_sn'] = $order_info->getOrderSn();
        return $this->findOneBy($condition);
    }

    /**
     * @throws Exception
     */
    public function getChangingNewOrderInfoBySubOutOrderId(string $sub_out_order_id): ?PlaneOrder
    {
        if (!$sub_out_order_id) {
            throw new Exception("请传入订单单号");
        }

        $p = $this->findOneByOrFail([
            'sub_out_order_id' => $sub_out_order_id,
            'change_flag'      => TripOrderState::ORDER_CHANGE_FLAG_NEW,
        ]);
        return $p?->order_info;
    }
}